/*
 * User: user
 * Date: 22/12/2007
 * Time: 12:47:07
 */
package org.conann.components;

import net.jcip.annotations.Immutable;
import org.conann.Stereotype;
import org.conann.configuration.Configuration;
import org.conann.documentation.ProvideBetterErrorMessages;
import org.conann.metadata.validation.WebBeansValidationException;
import static org.conann.util.DevelopmentUtil.unsupportedOperation;
import org.conann.util.StringUtils;

import javax.webbeans.Bean;
import javax.webbeans.Manager;
import javax.webbeans.binding.Named;
import javax.webbeans.scope.Dependent;
import java.lang.annotation.Annotation;

@Immutable
public class SimpleBean<T> extends AbstractBean<T> {

    public SimpleBean(Configuration configuration, Class<T> type) {
        super(configuration, type);
    }

    @Override
    protected String resolveName() {
        Class<T> type = getImplClass();
        if (type.isAnnotationPresent(Named.class)) {
            String namedValue = type.getAnnotation(Named.class).value();
            return namedValue == null ? namedValue : getDefaultName();
        }
        return null;
    }

    @Override
    protected String getDefaultName() {
        return StringUtils.uncapitalize(getImplClass().getSimpleName());
    }

    public T create(Manager manager) {
        throw unsupportedOperation();
    }

    public void destroy(Manager manager, T instance) {
        throw unsupportedOperation();
    }

    @Override
    @ProvideBetterErrorMessages("Specify the stereotypes and their scope types")
    protected Class<? extends Annotation> resolveScope() {
        if (getComponentMD().getScopeType() != null) {
            return getComponentMD().getScopeType();
        }
        Class<? extends Annotation> scopeInAllStereotypes = null;
        for (Stereotype stereotype : getComponentMD().getStereotypes()) {
            Class<? extends Annotation> stereotypeScopeType = stereotype.getScopeType();
            if (scopeInAllStereotypes == null) {
                scopeInAllStereotypes = stereotypeScopeType;
            } else {
                if (!scopeInAllStereotypes.equals(stereotypeScopeType)) {
                    throw new WebBeansValidationException("Invalid component definition [%s]:\nNot all stereotypes declare the same scope type.\nScope type must be declared explicitly", getImplClass().getName());
                }
                scopeInAllStereotypes = stereotypeScopeType;
            }
        }
        if (scopeInAllStereotypes == null) {
            // default for a Bean that doesn't define any scope
            return Dependent.class;
        }
        return scopeInAllStereotypes;
    }

    @SuppressWarnings({"unchecked"})
    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (other == null || getClass() != other.getClass()) {
            return false;
        }
        Bean<T> that = (Bean<T>) other;
        return getImplClass().equals(that.getImplClass());
    }

    @Override
    public int hashCode() {
        return getImplClass().hashCode();
    }

    @Override
    public String toString() {
        return "Simple component [" + getImplClass().getSimpleName() + ']';
    }
}